今天是第二十三我們可以寫一個javascript結合line bot天氣管理規劃行程網頁程式管理系統,以下是我的程式碼
首先,創建一個 LINE Bot 並記下您的 Channel Access Token
和 Channel Secret
。
這裡使用 OpenWeatherMap API 來獲取天氣資訊。你需要去 OpenWeatherMap 註冊並獲得 API key。
# 安裝必要的 Node.js package
npm install @line/bot-sdk axios express
const line = require('@line/bot-sdk');
const express = require('express');
const axios = require('axios');
const app = express();
const PORT = process.env.PORT || 3000;
const config = {
channelAccessToken: 'YOUR_CHANNEL_ACCESS_TOKEN',
channelSecret: 'YOUR_CHANNEL_SECRET',
};
// 初始化 LINE 客戶端
const client = new line.Client(config);
// OpenWeatherMap API 設置
const weatherAPIKey = 'YOUR_OPENWEATHERMAP_API_KEY';
const weatherAPIUrl = 'https://api.openweathermap.org/data/2.5/weather';
app.post('/webhook', line.middleware(config), (req, res) => {
Promise
.all(req.body.events.map(handleEvent))
.then(result => res.json(result))
.catch(err => console.log(err));
});
function handleEvent(event) {
if (event.type !== 'message' || event.message.type !== 'text') {
return Promise.resolve(null);
}
// 處理天氣查詢訊息
if (event.message.text.includes('天氣')) {
const city = event.message.text.replace('天氣', '').trim();
return getWeather(city)
.then(weatherMessage => {
return client.replyMessage(event.replyToken, {
type: 'text',
text: weatherMessage
});
})
.catch(err => {
console.error(err);
return client.replyMessage(event.replyToken, {
type: 'text',
text: '抱歉,我無法獲取天氣資訊。'
});
});
}
// 行程管理邏輯
if (event.message.text.includes('行程')) {
return manageSchedule(event.message.text)
.then(scheduleMessage => {
return client.replyMessage(event.replyToken, {
type: 'text',
text: scheduleMessage
});
});
}
return Promise.resolve(null);
}
async function getWeather(city) {
try {
const response = await axios.get(`${weatherAPIUrl}?q=${city}&appid=${weatherAPIKey}&units=metric&lang=zh_tw`);
const data = response.data;
const weather = data.weather[0].description;
const temp = data.main.temp;
return `目前${city}的天氣是${weather},氣溫約為 ${temp}°C。`;
} catch (error) {
return '無法獲取天氣資料,請檢查城市名稱是否正確。';
}
}
function manageSchedule(text) {
// 模擬行程管理邏輯,例如根據天氣自動調整
let scheduleMessage = '行程規劃如下:\n';
if (text.includes('戶外')) {
scheduleMessage += '建議根據天氣選擇適合的戶外活動。\n';
}
if (text.includes('室內')) {
scheduleMessage += '已為您安排適合的室內活動。\n';
}
return Promise.resolve(scheduleMessage);
}
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
接著是網頁部分,提供一個簡單的介面讓用戶輸入地點來查詢天氣,並透過天氣來管理行程規劃:
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>天氣行程管理系統</title>
<style>
body { font-family: Arial, sans-serif; background-color: #f0f8ff; padding: 20px; }
.container { max-width: 600px; margin: auto; text-align: center; }
input, button { padding: 10px; margin: 5px; width: 80%; }
#weather-result { margin-top: 20px; font-size: 1.2em; }
</style>
</head>
<body>
<div class="container">
<h1>行程規劃天氣管理系統</h1>
<p>請輸入城市來查詢天氣並安排行程:</p>
<input type="text" id="city-input" placeholder="輸入城市名稱">
<button onclick="getWeather()">查詢天氣</button>
<div id="weather-result"></div>
</div>
<script>
async function getWeather() {
const city = document.getElementById('city-input').value;
const apiKey = 'YOUR_OPENWEATHERMAP_API_KEY';
const apiUrl = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric&lang=zh_tw`;
try {
const response = await fetch(apiUrl);
const data = await response.json();
if (data.cod === 200) {
const weather = data.weather[0].description;
const temp = data.main.temp;
document.getElementById('weather-result').innerHTML = `
${city} 的天氣是 ${weather},氣溫 ${temp}°C。
`;
} else {
document.getElementById('weather-result').innerText = '查無此城市,請確認輸入正確。';
}
} catch (error) {
document.getElementById('weather-result').innerText = '無法獲取天氣資訊,請稍後再試。';
}
}
</script>
</body>
</html>
確保將 Webhook URL
設置為伺服器的網址,並開啟 LINE Developer 中的 Webhook 功能,讓 Bot 可以接收到訊息。
let videos = [];
這是一個用來儲存所有影片資料的空陣列,每個影片物件包含 title
和 file
屬性。在影片上傳時,我們會將影片的資訊加入這個陣列中,並在需要的時候更新或刪除。
renderVideoList
function renderVideoList() {
const videoList = document.getElementById('videoList');
videoList.innerHTML = ''; // 清空列表,避免重複渲染
if (videos.length === 0) {
videoList.innerHTML = '<tr><td colspan="2">目前沒有影片。</td></tr>';
return; // 如果沒有影片,顯示 "目前沒有影片"
}
videos.forEach((video, index) => {
const row = document.createElement('tr'); // 創建一個表格行
row.innerHTML = `
<td>${video.title}</td>
<td>
<button class="btn btn-warning btn-sm" onclick="editVideo(${index})">編輯</button>
<button class="btn btn-danger btn-sm" onclick="deleteVideo(${index})">刪除</button>
</td>
`;
videoList.appendChild(row); // 將每個影片資料添加到表格中
});
}
videoList.innerHTML = '';
:每次重新渲染影片列表前,先清空 videoList
內的內容,確保列表不會重複顯示。videos
陣列為空,則顯示「目前沒有影片」的提示,並終止渲染流程。forEach
遍歷:當有影片時,遍歷 videos
陣列,對每個影片創建一個 <tr>
(表格列),並動態插入影片標題與操作按鈕(編輯與刪除)。uploadForm
document.getElementById('uploadForm').addEventListener('submit', function(event) {
event.preventDefault(); // 阻止表單預設的提交行為(避免頁面重新載入)
const title = document.getElementById('videoTitle').value; // 取得影片標題
const file = document.getElementById('videoFile').files[0]; // 取得上傳的影片檔案
if (!file) {
alert('請選擇影片檔案。');
return; // 如果沒有選擇檔案,提示並結束函數
}
const video = {
title: title,
file: file // 將影片標題和檔案保存為一個物件
};
videos.push(video); // 將新影片資料推入 videos 陣列中
renderVideoList(); // 重新渲染影片列表
this.reset(); // 重置表單內容
});
event.preventDefault()
:阻止表單提交的預設行為,這樣表單提交後不會刷新頁面。document.getElementById('videoTitle').value
取得影片標題。document.getElementById('videoFile').files[0]
取得選擇的影片檔案。videos
陣列。renderVideoList()
來更新 UI。this.reset()
:重置表單,清空所有欄位。editVideo
function editVideo(index) {
const newTitle = prompt('請輸入新的影片標題', videos[index].title); // 使用者輸入新標題
if (newTitle !== null && newTitle.trim() !== '') { // 確保新標題有效
videos[index].title = newTitle; // 更新影片標題
renderVideoList(); // 重新渲染影片列表
}
}
prompt()
:彈出一個對話框,讓使用者輸入新的影片標題。初始值為當前影片的標題。null
,則更新影片標題。videos
陣列中的標題後,重新渲染影片列表。deleteVideo
function deleteVideo(index) {
if (confirm('確定要刪除此影片嗎?')) { // 彈出確認對話框
videos.splice(index, 1); // 從陣列中刪除該影片
renderVideoList(); // 重新渲染影片列表
}
}
confirm()
:彈出確認對話框,詢問使用者是否確定刪除影片。如果使用者點擊「確認」,則繼續執行刪除操作。videos.splice(index, 1)
:從 videos
陣列中移除指定索引的影片。splice()
是一個用來移除陣列中元素的方法,第一個參數是起始位置,第二個參數是刪除的數量(1 表示刪除一個元素)。renderVideoList();
這行程式在頁面載入時即被執行,確保影片列表一開始就正確顯示,即使當前 videos
陣列是空的也能顯示提示「目前沒有影片」。
videos
陣列 是這個系統的核心,負責儲存所有上傳的影片資料。renderVideoList
函數會根據 videos
陣列中的內容動態生成影片列表,並在影片更新、刪除或修改後重新渲染頁面。